package io.noties.markwon.app.widget;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import ohos.agp.components.Attr;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.app.Context;

/**
 * @author: yangrui
 * @function: FlowLayout
 * @date: 2021/3/23
 */
public class FlowLayout extends ComponentContainer {

    private int spacingVertical;
    private int spacingHorizontal;
    private final List<LayoutParam> layoutConfigs = new ArrayList<>();
    private int defaultSpacing = 8;

    public FlowLayout(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttrSet attrs) {
        Optional<Attr> flSpacing = attrs.getAttr("" +
            "");
        flSpacing.ifPresent(attr -> defaultSpacing = attr.getIntegerValue());

        Optional<Attr> flSpacingHorizontal = attrs.getAttr("fl_spacingHorizontal");
        flSpacingHorizontal.ifPresent(attr -> spacingHorizontal = attr.getIntegerValue());
        if (spacingHorizontal == 0) {
            spacingHorizontal = defaultSpacing;
        }

        Optional<Attr> flSpacingVertical = attrs.getAttr("fl_spacingVertical");
        flSpacingVertical.ifPresent(attr -> spacingVertical = attr.getIntegerValue());
        if (spacingVertical == 0) {
            spacingVertical = defaultSpacing;
        }

        onMeasure();
        layout();
    }

    private void onMeasure() {
        // we must have width (match_parent or exact dimension)
        setEstimateSizeListener((widthMeasureSpec, heightMeasureSpec) -> {
            int width = MeasureSpec.getSize(widthMeasureSpec);
            if (width <= 0) {
                return false;
            }

            int availableWidth = width - getPaddingLeft() - getPaddingRight();
            int childWidthSpec = EstimateSpec.getSizeWithMode(availableWidth, MeasureSpec.NOT_EXCEED);
            int childHeightSpec = EstimateSpec.getSizeWithMode(0, MeasureSpec.UNCONSTRAINT);

            int x = 0;
            int y = 0;
            int lineHeight = 0;
            for (int i = 0; i < getChildCount(); i++) {
                Component child = getComponentAt(i);

                // LayoutConfig layoutConfig = child.getLayoutConfig();

                if (child.getVisibility() == Component.HIDE) {
                    continue;
                }

                child.estimateSize(childWidthSpec, childHeightSpec);

                int measuredWidth = child.getEstimatedWidth();
                if (measuredWidth > (availableWidth - x)) {
                    // new line
                    // make next child start at child measure width (starting at x = 0)
                    layoutConfigs.add(new LayoutParam(0, y + lineHeight + spacingVertical));
                    x = measuredWidth + spacingHorizontal;
                    // move vertically by max value of child height on this line
                    y += lineHeight + spacingVertical;

                    lineHeight = child.getEstimatedHeight();

                } else {
                    // we fit this line
                    layoutConfigs.add(new LayoutParam(x, y));
                    x += measuredWidth + spacingHorizontal;
                    lineHeight = Math.max(lineHeight, child.getEstimatedHeight());
                }
            }
            int height = y + lineHeight + getPaddingTop() + getPaddingBottom();

            setEstimatedSize(width, height);
            return false;
        });
    }


    private void layout() {
        setArrangeListener((l, t, r, b) -> {
            for (int i = 0; i < getChildCount(); i++) {
                Component child = getComponentAt(i);
                // LayoutConfig layoutConfig = child.getLayoutConfig();

                int left = child.getPaddingLeft() + layoutConfigs.get(i).x;
                int top = child.getPaddingTop() + layoutConfigs.get(i).y;

                child.setComponentPosition(
                    left,
                    top,
                    left + child.getEstimatedWidth(),
                    top + child.getEstimatedWidth()
                );

            }
            return false;
        });
    }

    /**
     * TODO lack api
     *
     * @return LayoutConfig
     */
    private LayoutConfig generateDefaultLayoutParams() {
        return new LayoutParam();
    }

    public boolean checkLayoutParams(LayoutConfig params) {
        return params instanceof LayoutConfig;
    }

    public LayoutConfig generateLayoutParams(AttrSet attrs) {
        return new LayoutParam(getContext(), attrs);
    }

    public LayoutConfig generateLayoutParams(LayoutConfig layoutParams) {
        return new LayoutParam(layoutParams);
    }

    class LayoutParam extends LayoutConfig {
        int x, y;

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }


        private LayoutParam(int x, int y) {
            this.x = x;
            this.y = y;
        }

        private LayoutParam(Context context, AttrSet attrs) {
            super(context, attrs);
        }

        private LayoutParam(LayoutConfig layoutParams) {
            super(layoutParams);
        }

        private LayoutParam() {
            // this(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        }

    }


}